package com.roadmap.client.auth;

import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.roadmap.common.BaseConst;
import com.roadmap.common.BaseEntity;
import com.roadmap.common.BaseUtility;
import com.roadmap.common.RdcLogger;
import com.roadmap.common.RdcResourceBundle;
import com.roadmap.entities.Aspirant;
import com.roadmap.entities.Registration;
import com.roadmap.exception.EntityNotFoundException;
import com.roadmap.exception.InvalidActionException;
import com.roadmap.exception.InvalidValueException;
import com.roadmap.exception.LogonException;
import com.roadmap.exception.NotMatchedException;
import com.roadmap.exception.NotRegisteredException;
import com.roadmap.exception.NullObjectException;
import com.roadmap.exception.ServerException;
import com.roadmap.repo.db.DatabaseUtility;
import com.roadmap.repo.db.IDatabaseUtility;
import com.roadmap.util.RdcEncryptor;
import com.roadmap.util.mail.MailDispatcher;

public class AuthServices implements IAuthServices {
	private final static Logger logger = RdcLogger
			.getLogger(AuthServices.class);

	private final IDatabaseUtility dbUtil = new DatabaseUtility();

	public Aspirant logon(String mail, String password, String ipAddr)
			throws InvalidActionException, ServerException,
			NullObjectException, InvalidValueException, LogonException {
		String errorMsg = null;
		if (mail == null || password == null || mail.trim().equals("")
				|| password.trim().equals("") || ipAddr == null) {
			NullObjectException ex = new NullObjectException();
			errorMsg = "Mail or password can't be empty.";
			logger.error(errorMsg, ex);
			throw ex;
		}

		Aspirant asp = getAspirant(mail);
		if (asp != null) {
			// the password stored in database is encrypted, so before comparing
			// them, decode it.
			String pwrd = RdcEncryptor.getInstace().decode(
					asp.getLoginPassword());
			if (password.equals(pwrd)) {
				asp.setLoginIP(ipAddr);
				asp.setUpdatedTime(new Date());
				dbUtil.update(asp);
				return asp;
			}
		}

		logger.error(mail
				+ " as an user can't log on due to wrong credentials.");
		LogonException nle = new LogonException();
		throw nle;
	}

	private Aspirant getAspirant(String mail) throws InvalidActionException,
			ServerException, NullObjectException, InvalidValueException {
		String criteria = "mail='" + mail + "'";
		List list = dbUtil.getEntitiesByCriteria(Aspirant.class, criteria);
		if (list != null && list.size() > 0)
			return (Aspirant) (list.get(0));
		return null;
	}

	public String getTempPassword(String mail, String ip)
			throws NullObjectException, ServerException, InvalidValueException,
			InvalidActionException, NotRegisteredException {
		IRegisterServices userReg = new RegisterServices();
		Registration reg = userReg.getRegFromDB(mail);
		if (reg == null
				|| reg.getStatus() == BaseConst.REGISTRATION_STATUS_NotPassed) {
			NotRegisteredException nre = new NotRegisteredException();
			logger.error("the mail is not registered yet.", nre);
			throw nre;
		}

		String tempPassword = BaseUtility.getRandomString();
		Aspirant asp = getAspirant(mail);
		if(asp == null) {
			NotRegisteredException nre = new NotRegisteredException();
			logger.error("the mail is not registered yet.", nre);
			throw nre;
		}
		asp.setLoginPassword(RdcEncryptor.getInstace().encode(tempPassword));
		asp.setLoginIP(ip);
		asp.setUpdatedTime(new Date());
		dbUtil.update(asp);

		sendMail(mail, RdcResourceBundle.PWD_MAIL_CONTENT + tempPassword);

		return tempPassword;
	}

	public void resetPassword(String asprantId, String oldPassword,
			String newPassword) throws NullObjectException, ServerException,
			InvalidValueException, InvalidActionException,
			EntityNotFoundException, NotMatchedException {
		if (asprantId == null || oldPassword == null || newPassword == null) {
			NullObjectException noe = new NullObjectException();
			logger.error(
					"aspirantId, old password or new password can't be NULL",
					noe);
			throw noe;
		}

		BaseEntity entity = dbUtil.getEntityById(Aspirant.class, asprantId);
		if (entity == null) {
			EntityNotFoundException nfe = new EntityNotFoundException();
			logger.error("no user info was found to match the this ID: "
					+ asprantId);
			throw nfe;
		}

		Aspirant asp = (Aspirant) entity;
		String pwrd = RdcEncryptor.getInstace().decode(asp.getLoginPassword());
		if (!oldPassword.equals(pwrd)) {
			NotMatchedException ive = new NotMatchedException();
			String msg = "the old password doesn't match user's password.";
			logger.error(msg, ive);
			throw ive;
		}
		else if (oldPassword.equals(newPassword)) {
			return;
		}
		else {
			asp.setLoginPassword(RdcEncryptor.getInstace().encode(newPassword));
			asp.setUpdatedTime(new Date());
			dbUtil.update(asp);
		}
	}

	/** mail the temporary mail to the user */
	private boolean sendMail(String mailAddr, String message) {
		return MailDispatcher.send(mailAddr,
				RdcResourceBundle.PWD_MAIL_SUBJECT, message);
	}

}
